# PrimaryKeyResolver.java

    package org.codefilarete.stalactite.engine.configurer.dslresolver;

    import java.util.Map;

    import org.codefilarete.reflection.AccessorDefinition;
    import org.codefilarete.reflection.ReadWritePropertyAccessPoint;
    import org.codefilarete.stalactite.dsl.entity.EntityMappingConfiguration.CompositeKeyMapping;
    import org.codefilarete.stalactite.dsl.entity.EntityMappingConfiguration.KeyMapping;
    import org.codefilarete.stalactite.dsl.entity.EntityMappingConfiguration.SingleKeyMapping;
    import org.codefilarete.stalactite.dsl.idpolicy.GeneratedKeysPolicy;
    import org.codefilarete.stalactite.dsl.key.CompositeKeyMappingConfiguration;
    import org.codefilarete.stalactite.dsl.naming.ColumnNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.UniqueConstraintNamingStrategy;
    import org.codefilarete.stalactite.engine.configurer.builder.embeddable.EmbeddableMapping;
    import org.codefilarete.stalactite.engine.configurer.builder.embeddable.EmbeddableMappingBuilder;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.ddl.structure.PrimaryKey;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.statement.binder.ColumnBinderRegistry;
    import org.codefilarete.tool.VisibleForTesting;

    import static org.codefilarete.tool.Nullable.nullable;

    public class PrimaryKeyResolver<C, I> {

    	/**
    	 * Creates a primary key on a table that owns the identification
    	 *
    	 * @param keyLinkage information that allow to create primary key
    	 * @return the created {@link PrimaryKey}
    	 */
    	@VisibleForTesting
    	public <T extends Table<T>> PrimaryKey<T, I> addIdentifyingPrimarykey(KeyMapping<C, I> keyLinkage,
    	                                                                      T pkTable,
    	                                                                      ColumnBinderRegistry columnBinderRegistry,
    	                                                                      ColumnNamingStrategy columnNamingStrategy,
    	                                                                      UniqueConstraintNamingStrategy uniqueConstraintNamingStrategy) {
    		AccessorDefinition identifierDefinition = AccessorDefinition.giveDefinition(keyLinkage.getAccessor());
    		if (keyLinkage instanceof CompositeKeyMapping) {
    			CompositeKeyMappingConfiguration<I> configuration = ((CompositeKeyMapping<C, I>) keyLinkage).getCompositeKeyMappingBuilder().getConfiguration();
    			// Note that we won't care about readonly column returned by build(..) since we're on a primary key case, then
    			// some readonly columns would be nonsense
    			EmbeddableMappingBuilder<I, T> compositeKeyBuilder = new EmbeddableMappingBuilder<>(configuration, pkTable, columnBinderRegistry, columnNamingStrategy, uniqueConstraintNamingStrategy);
    			EmbeddableMapping<I, T> build = compositeKeyBuilder.build();
    			Map<ReadWritePropertyAccessPoint<I, ?>, Column<T, ?>> compositeKeyMapping = build.getMapping();
    			compositeKeyMapping.values().forEach(Column::primaryKey);
    		} else {
    			SingleKeyMapping<C, I> singleKeyLinkage = (SingleKeyMapping<C, I>) keyLinkage;
    			String columnName = determineColumnName(singleKeyLinkage, columnNamingStrategy);
    			// nullability = false may not be necessary because of primary key, let for principle
    			Column<?, I> primaryKey = pkTable.addColumn(columnName, identifierDefinition.getMemberType(), singleKeyLinkage.getColumnOptions().getColumnSize(), false);
    			primaryKey.primaryKey();
    			if (singleKeyLinkage.getIdentifierPolicy() instanceof GeneratedKeysPolicy) {
    				primaryKey.autoGenerated();
    			}
    		}
    		return pkTable.getPrimaryKey();
    	}

    	private <O> String determineColumnName(SingleKeyMapping<C, O> keyLinkage, ColumnNamingStrategy columnNamingStrategy) {
    		return nullable(keyLinkage.getColumnOptions().getColumnName())
    				.elseSet(keyLinkage::getFieldName)
    				.elseSet(() -> columnNamingStrategy.giveName(AccessorDefinition.giveDefinition(keyLinkage.getAccessor())))
    				.get();
    	}
    }